package com.maelarak.android.lolcharbuilder.tools.parsers;

import android.util.Log;

import com.maelarak.android.lolcharbuilder.config.GameProperties;
import com.maelarak.android.lolcharbuilder.config.SoftwareProperties;
import com.maelarak.android.lolcharbuilder.models.Build;
import com.maelarak.android.lolcharbuilder.models.Champion;
import com.maelarak.android.lolcharbuilder.models.Item;
import com.maelarak.android.lolcharbuilder.models.Skill;
import com.maelarak.android.lolcharbuilder.models.SkillType;
import com.maelarak.android.lolcharbuilder.models.Stat;
import com.maelarak.android.lolcharbuilder.models.StatType;
import com.maelarak.android.lolcharbuilder.tools.exceptions.SaveException;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

/**
 * Created by MaelArak on 09/06/13.
 */
public class XMLParser {

    private static final String CLASSTAG = "XMLParser";
    Document document;
    Element racine;
    StringBuffer titre;
    ArrayList<Build> buildList;
    ArrayList<Champion> championList;
    ArrayList<Item> itemList;

    public XMLParser() {
        super();
        buildList = this.parseBuild();
        championList = this.parseChampion();
        itemList = this.parseItem();
    }

    private ArrayList<Build> parseBuild(){
        ArrayList<Build> buildList = new ArrayList<Build>();
        SAXBuilder sxb = new SAXBuilder();
        try
        {
            FileReader myDoc = new FileReader(SoftwareProperties.BUILDS_XML_LOCATION);
            document = sxb.build(myDoc);
            myDoc.close();
        } catch(JDOMException jdome){
            Log.d(CLASSTAG, jdome.toString());
        } catch(FileNotFoundException fnfe){
            Log.d(CLASSTAG, fnfe.toString());
        } catch(IOException ioe){
            Log.d(CLASSTAG, ioe.toString());
        }
        racine = document.getRootElement();

        ArrayList<Element> builds = new ArrayList<Element>(racine.getChildren("build"));

        for (Element build : builds){
            Build b = new Build();

            boolean isLastUsed = Boolean.valueOf(build.getAttributeValue("lastread"));
            b.setLastUsed(isLastUsed);

            titre = new StringBuffer(build.getChild("title").getValue());
            b.setBuildname(titre);

            String champion = build.getChild("champion").getValue();
            b.setCharacter(new Champion(champion));

            Element item_child = build.getChild("items");
            ArrayList<Element> item_list = new ArrayList<Element>(item_child.getChildren());
            ArrayList<Item> items = new ArrayList<Item>(item_list.size());

            for (Element e : item_list){
                Item i = new Item(new StringBuffer(e.getValue()));
                items.add(i);
            }
            b.setItemlist(items);

            Element skillorder = build.getChild("skillorder");
            ArrayList<Element> skill_list = new ArrayList<Element>(skillorder.getChildren());
            for (Element e : skill_list){
                Log.i(CLASSTAG,e.getChildText("order")+" : "+e.getChildText("value"));
                b.addSkill(new Skill(SkillType.valueOf(e.getChildText("value"))));
            }
            buildList.add(b);
        }
        return buildList;
    }

    private ArrayList<Champion> parseChampion(){
        ArrayList<Champion> championList = new ArrayList<Champion>();
        SAXBuilder sxb = new SAXBuilder();
        try
        {
            FileReader myDoc = new FileReader(SoftwareProperties.BUILDS_XML_LOCATION);
            document = sxb.build(myDoc);
            myDoc.close();
        } catch(JDOMException jdome){
            Log.d(CLASSTAG, jdome.toString());
        } catch(FileNotFoundException fnfe){
            Log.d(CLASSTAG, fnfe.toString());
        } catch(IOException ioe){
            Log.d(CLASSTAG, ioe.toString());
        }
        racine = document.getRootElement();

        ArrayList<Element> champions = new ArrayList<Element>(racine.getChildren("champion"));
        for (Element champion : champions){
            String name = champion.getChildText("name");
            int number = Integer.valueOf(champion.getChildText("number"));
            Element sklist = champion.getChild("skills");
            ArrayList<Element> skills = new ArrayList<Element>(sklist.getChildren("skill"));
            ArrayList<Skill> skillList = new ArrayList<Skill>(GameProperties.NUMBER_OF_SKILLS);
            for (Element skill : skills) {
                String skillname = skill.getChildText("name");
                SkillType skilltype = SkillType.valueOf(skill.getChildText("order"));
                skillList.add(new Skill(skillname,skilltype));
            }
            Champion c = new Champion(name,number,skillList);
            championList.add(c);
        }
        return championList;
    }

    private ArrayList<Item> parseItem(){
        ArrayList<Build> buildList = new ArrayList<Build>();
        SAXBuilder sxb = new SAXBuilder();
        try
        {
            FileReader myDoc = new FileReader(SoftwareProperties.ITEMS_XML_LOCATION);
            document = sxb.build(myDoc);
            myDoc.close();
        } catch (JDOMException jdome){
            Log.d(CLASSTAG,jdome.toString());
        } catch (FileNotFoundException fnfe){
            Log.d(CLASSTAG,fnfe.toString());
        } catch(IOException ioe) {
            Log.d(CLASSTAG, ioe.toString());
        }
        racine = document.getRootElement();
        ArrayList<Element> items = new ArrayList<Element>(racine.getChildren("items"));
        ArrayList<Item> itemsList = new ArrayList<Item>(items.size());
        for (Element item : items){
            Item i = new Item();

            StringBuffer name = new StringBuffer(item.getChild("name").getValue());
            i.setName(name);
            name = null;

            StringBuffer price = new StringBuffer(item.getChild("fullprice").getValue());
            i.setFullPrice(Integer.parseInt(price.toString()));
            price = null;

            Element recipe_tag = item.getChild("recipe");
            StringBuffer recipe_price = new StringBuffer(recipe_tag.getChild("price").getValue());
            i.setRecipePrice(Integer.parseInt(recipe_price.toString()));
            recipe_price=null;

            ArrayList<Element> item_list = new ArrayList<Element>(recipe_tag.getChildren("item"));
            ArrayList<Item> items_recipe = new ArrayList<Item>(item_list.size());

            for (Element e : item_list){
                Item ir = new Item(new StringBuffer(e.getValue()));
                items_recipe.add(ir);
            }
            i.setRecipe(items_recipe);

            Element stats = item.getChild("statlist");
            ArrayList<Element> stat_list = new ArrayList<Element>(stats.getChildren());
            ArrayList<Stat> statList = new ArrayList<Stat>(stat_list.size());
            for (Element e : stat_list){
                StatType stat_type = StatType.valueOf(e.getChild("type").getText());
                int stat_value = Integer.parseInt(e.getChild("value").getText());
                Stat s = new Stat(stat_type,stat_value);
                statList.add(s);
            }
            i.setRecipe(itemList);
            itemsList.add(i);
        }
        return itemsList;
    }

    public void addBuild(Build b){
        for (Build build : buildList){
            if (build.getBuildname().equals(titre)){
                buildList.remove(build);
            }
        }
        buildList.add(b);
    }

    public void saveBuilds(){
        generateBuildXML();
        try
        {
            XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
            FileOutputStream buildXML =
                    new FileOutputStream(SoftwareProperties.BUILDS_XML_LOCATION);
            sortie.output(racine, buildXML);
            buildXML.close();
        }
        catch (java.io.IOException ioe){
            Log.d(CLASSTAG, "erreur du save() IOException".concat(ioe.toString()));
        }
    }

    private void saveChampions() throws SaveException {
        generateChampionXML();
        try
        {
            XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
            FileOutputStream championXML =
                    new FileOutputStream(SoftwareProperties.CHAMPIONS_XML_LOCATION);
            sortie.output(racine, championXML);
            championXML.close();
        }
        catch (java.io.IOException ioe){
            Log.d(CLASSTAG, "Erreur de saveChampions() IOException".concat(ioe.toString()));
            throw new SaveException();
        }
    }

    private void saveItems() throws SaveException{
        generateItemsXML();
        try
        {
            //On utilise ici un affichage classique avec getPrettyFormat()
            XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
            //Remarquez qu'il suffit simplement de créer une instance de FileOutputStream
            //avec en argument le nom du fichier pour effectuer la sérialisation.
            FileOutputStream itemsXML =
                    new FileOutputStream(SoftwareProperties.ITEMS_XML_LOCATION);
            sortie.output(racine, itemsXML);
            itemsXML.close();
        }
        catch (java.io.IOException ioe){
            Log.w(CLASSTAG, "erreur du saveItems() IOException".concat(ioe.toString()));
            throw new SaveException();
        }
    }

    private void generateBuildXML(){
        racine = new Element("builds");
        for (Build build : buildList){
            Element balise_build = new Element("build");
            if (build.isLastUsed()){
                balise_build.setAttribute("lastread","true");
            }
            Element balise_titre = new Element("title");
            balise_titre.setText(build.getBuildname().toString());
            Element balise_champion = new Element("champion");
            balise_champion.setText(build.getCharacter().getName());
            Element balise_skillorder = new Element("skillorder");
            for(Skill s : build.getSkilllist()){
                Element balise_skill = new Element("skill");
                Element balise_value = new Element("value");
                balise_value.setText(s.getType().toString());
                balise_skill.addContent(balise_value);
                balise_skillorder.addContent(balise_skill);
            }
            Element balise_items = new Element("items");
            for(Item i : build.getItemlist()){
                Element balise_item = new Element("item");
                balise_item.setText(i.getName().toString());
                balise_items.addContent(balise_item);
            }
            balise_build.addContent(balise_titre);
            balise_build.addContent(balise_champion);
            balise_build.addContent(balise_skillorder);
            balise_build.addContent(balise_items);
            racine.addContent(balise_build);
        }
    }

    private void generateChampionXML(){
        racine = new Element("champions");
        for (Champion champion : championList){
            Element balise_champion = new Element("champion");
            Element balise_name = new Element("name");
            balise_name.setText(champion.getName());
            Element balise_number = new Element("number");
            balise_number.setText(String.valueOf(champion.getNumber()));
            Element balise_skills = new Element("skills");
            for (Skill s : champion.getSkillList()){
                Element balise_skill = new Element("skill");
                Element balise_order = new Element("order");
                balise_order.setText(s.getType().toString());
                Element balise_skillname = new Element("name");
                balise_skillname.setText(s.getName());
                balise_skill.addContent(balise_order);
                balise_skill.addContent(balise_skillname);
                balise_skills.addContent(balise_skill);
            }
            balise_champion.addContent(balise_name);
            balise_champion.addContent(balise_number);
            balise_champion.addContent(balise_skills);
            racine.addContent(balise_champion);
        }
    }

    private void generateItemsXML(){
        racine = new Element("items");
        for (Item item : itemList){
            Element balise_item = new Element("item");
            Element balise_name = new Element("name");
            balise_name.setText(item.getName());
            balise_item.addContent(balise_name);
            Element balise_fullprice = new Element("fullprice");
            balise_fullprice.setText(String.valueOf(item.getFullPrice()));
            balise_item.addContent(balise_fullprice);
            if (item.getRecipe()!=null){
                Element balise_recipe = new Element("recipe");
                Element balise_recipe_price = new Element("price");
                balise_recipe_price.setText(String.valueOf(item.getRecipePrice()));
                balise_recipe.addContent(balise_recipe_price);
                for (Item i : item.getRecipe()){
                    Element balise_item_recipe = new Element("item");
                    balise_item_recipe.setText(i.getName());
                    balise_recipe.addContent(balise_item_recipe);
                }
                balise_item.addContent(balise_recipe);
            }
            Element balise_statlist = new Element("statlist");
            for (Stat stat : item.getStatList()){
                Element balise_stat = new Element("stat");
                Element balise_type = new Element("type");
                balise_type.setText(stat.getStat_type().toString());
                balise_stat.addContent(balise_type);
                Element balise_value = new Element("value");
                balise_value.setText(String.valueOf(stat.getValue()));
                balise_stat.addContent(balise_value);
                balise_statlist.addContent(balise_stat);
            }
            balise_item.addContent(balise_statlist);
            racine.addContent(balise_item);
        }
    }

    protected Boolean update(ArrayList<Champion> champs, ArrayList<Item> items){
        Boolean code_retour = Boolean.valueOf(false);
        try{
            this.championList = champs;
            saveChampions();
            this.itemList = items;
            saveItems();
            code_retour = Boolean.valueOf(true);
        } catch (SaveException se){
            Log.d(CLASSTAG, "erreur de sauvegarde".concat(se.toString()));
        }
        return code_retour;
    }

    public Build getBuild(StringBuffer titre){
        Build b = null;
        for (Build build : buildList) {
            if (build.getBuildname().equals(titre)){
                b = build;
            }
        }
        return b;
    }

}
